﻿' LibWowArmory
' by Ronald M. Clifford (roncli@roncli.com)
'
' This source code is released under the GNU Library General Public License (LGPL) Version 2.1.

Imports System.Collections
Imports System.IO
Imports System.Net
Imports System.Reflection
Imports System.Security
Imports System.Text
Imports System.Threading
Imports System.Web

Namespace roncliProductions.LibWowArmory

    ''' <summary>
    ''' The base class to inherit Armory info from
    ''' </summary>
    ''' <remarks></remarks>
    Public MustInherit Class WowArmoryData

        Protected strData As String
        Private strUsername As String
        Private strPassword As String

        ''' <summary>
        ''' The URL that will open the appropriate armory page
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public MustOverride ReadOnly Property URL() As String

        ''' <summary>
        ''' A boolean value that determines whether or not you are required to login to the Armory before accessing the data
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public MustOverride ReadOnly Property RequiresLogin() As Boolean

        ''' <summary>
        ''' The username of the account you wish to log in to the Armory with
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Username() As String
            Get
                Return strUsername
            End Get
            Set(ByVal value As String)
                strUsername = value
            End Set
        End Property

        ''' <summary>
        ''' The password of the account you wish to log in to the Armory with
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Password() As String
            Get
                Return strPassword
            End Get
            Set(ByVal value As String)
                strPassword = value
            End Set
        End Property

        Private Property ArmoryCookie() As CookieContainer
            Get
                If Cache.Cache("LibWoWArmory.ArmoryCookie") Is Nothing Then
                    Return New CookieContainer
                End If
                Dim ccCookies As CookieContainer = CType(Cache.Cache("LibWoWArmory.ArmoryCookie"), CookieContainer)
                Dim htCookies As Hashtable = CType(ccCookies.GetType().InvokeMember("m_domainTable", BindingFlags.NonPublic Or BindingFlags.GetField Or BindingFlags.Instance, Nothing, ccCookies, New Object() {}), Hashtable)
                For Each strKey As String In New ArrayList(htCookies.Keys)
                    If strKey.StartsWith(".") Then
                        htCookies(strKey.Substring(1)) = htCookies(strKey)
                    End If
                Next
                Return ccCookies
            End Get
            Set(ByVal value As CookieContainer)
                Cache.Cache.Insert("LibWoWArmory.ArmoryCookie", value, Nothing, Date.UtcNow.AddDays(1), Nothing, Caching.CacheItemPriority.NotRemovable, Nothing)
            End Set
        End Property

        ''' <summary>
        ''' Retrieves the data based on the supplied query
        ''' </summary>
        ''' <remarks></remarks>
        Protected Sub Retrieve()
            If RequiresLogin Then
                If Not CheckLogin() Then
                    ArmoryLogin(strUsername, strPassword)
                    If Not CheckLogin() Then
                        Throw New SecurityException("You could not be logged in to the Armory.  Check your username and password.")
                        Exit Sub
                    End If
                End If
            End If

            Dim hwrRequest As HttpWebRequest = CType(HttpWebRequest.Create(URL), HttpWebRequest)
            hwrRequest.Accept = "*/*"
            hwrRequest.UserAgent = "MSIE 7.0"
            hwrRequest.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-us")
            hwrRequest.Headers.Add(HttpRequestHeader.Pragma, "no-cache")
            hwrRequest.CookieContainer = ArmoryCookie
            hwrRequest.Timeout = 10000
            Try
                Using wrResponse As WebResponse = hwrRequest.GetResponse()
                    Using srReader As New StreamReader(wrResponse.GetResponseStream())
                        strData = srReader.ReadToEnd()
                    End Using
                    For Each cCookie As Cookie In CType(wrResponse, HttpWebResponse).Cookies
                        hwrRequest.CookieContainer.Add(cCookie)
                    Next
                    ArmoryCookie = hwrRequest.CookieContainer
                End Using
            Catch wex As WebException
                If wex.Response Is Nothing Then Throw wex
                If CType(wex.Response, HttpWebResponse).StatusCode = HttpStatusCode.NotFound Then
                    strData = ""
                Else
                    Throw wex
                End If
            End Try
            hwrRequest = Nothing
        End Sub

        Private Sub ArmoryLogin(ByVal strUsername As String, ByVal strPassword As String)
            Dim hwrRequest As HttpWebRequest = CType(HttpWebRequest.Create("http://www.wowarmory.com/?login=1"), HttpWebRequest)
            hwrRequest.Accept = "*/*"
            hwrRequest.UserAgent = "MSIE 7.0"
            hwrRequest.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-us")
            hwrRequest.Headers.Add(HttpRequestHeader.Pragma, "no-cache")
            hwrRequest.CookieContainer = ArmoryCookie
            hwrRequest.Timeout = 10000
            Using wrResponse As WebResponse = hwrRequest.GetResponse()
                Using srReader As New StreamReader(wrResponse.GetResponseStream())
                    Dim strNull As String = srReader.ReadToEnd()
                End Using
                For Each cCookie As Cookie In CType(wrResponse, HttpWebResponse).Cookies
                    hwrRequest.CookieContainer.Add(cCookie)
                Next
                ArmoryCookie = hwrRequest.CookieContainer
            End Using
            hwrRequest = Nothing

            hwrRequest = CType(HttpWebRequest.Create("https://us.battle.net/login/login.xml?ref=http%3A%2F%2Fwww.wowarmory.com%2Findex.xml&app=armory"), HttpWebRequest)
            hwrRequest.Accept = "*/*"
            hwrRequest.UserAgent = "MSIE 7.0"
            hwrRequest.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-us")
            hwrRequest.Headers.Add(HttpRequestHeader.Pragma, "no-cache")
            hwrRequest.CookieContainer = ArmoryCookie
            hwrRequest.Timeout = 10000
            Dim strPostData As String = String.Format("accountName={0}&password={1}", HttpUtility.UrlEncode(strUsername), HttpUtility.UrlEncode(strPassword))
            Dim bytPostData() As Byte = Encoding.ASCII.GetBytes(strPostData)
            hwrRequest.Method = "POST"
            hwrRequest.ContentType = "application/x-www-form-urlencoded"
            hwrRequest.ContentLength = bytPostData.Length
            Using sStream As Stream = hwrRequest.GetRequestStream()
                sStream.Write(bytPostData, 0, bytPostData.Length)
                sStream.Close()
            End Using
            Using wrResponse As WebResponse = hwrRequest.GetResponse()
                Using srReader As New StreamReader(wrResponse.GetResponseStream())
                    Dim strNull As String = srReader.ReadToEnd()
                    If Not wrResponse.ResponseUri.ToString().StartsWith("http://www.wowarmory.com/index.xml?ST=") Then
                        Stop
                    End If
                End Using
                For Each cCookie As Cookie In CType(wrResponse, HttpWebResponse).Cookies
                    hwrRequest.CookieContainer.Add(cCookie)
                Next
                ArmoryCookie = hwrRequest.CookieContainer
            End Using
            hwrRequest = Nothing
        End Sub

        Private Function CheckLogin() As Boolean
            Dim lsStatus As New roncliProductions.LibWowArmory.LoginStatus
            Return Not String.IsNullOrEmpty(lsStatus.LoggedInUsername)
        End Function

    End Class

End Namespace